﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Xml;
using System.Reflection;
using Coffee.SurveyControls;
using Coffee.SurveyControls.SurveyQuestions;

namespace Coffee
{
    public class SurveyQuestionRowFactory
    {
        private const string SQHandlerNameSpace = "SurveyQuestionHandler";

        static Dictionary<string, Type> sqcontroltypes;

        public static void RegisterType(Type type)
        {
            if ((typeof(SurveyQuestionRow)).IsAssignableFrom(type))
            {
                if (!SQControlTypes.ContainsKey(type.Name))
                    SQControlTypes.Add(type.Name, type);
            }
            else
            {
                throw new Exception("Invalid type");
            }
        }

        public static Dictionary<string, Type> SQControlTypes
        {
            get
            {
                if (sqcontroltypes == null)
                {
                    sqcontroltypes = new Dictionary<string, Type>();

                    var types = Assembly
                        .GetExecutingAssembly()
                        .GetTypes()
                        .Where(m => typeof(SurveyQuestionRow).IsAssignableFrom(m));

                    foreach (Type type in types)
                    {
                        sqcontroltypes.Add(type.Name, type);
                    }
                }
                return sqcontroltypes;
            }
        }

        public static TypeKeyedCache<Func<SurveyControl, XmlNode, SurveyQuestionRow>> surveyQuestionRowCache = new TypeKeyedCache<Func<SurveyControl, XmlNode, SurveyQuestionRow>>();

        public static SurveyQuestionRow Create(SurveyControl parent, XmlNode configuration)
        {
            // Resolve Types...
            string key = "SQ" + configuration.Attributes["type"].Value;

            if (SQControlTypes.ContainsKey(key))
            {
                var type = SQControlTypes[key];

                Func<SurveyControl, XmlNode, SurveyQuestionRow> func = null;

                if (!surveyQuestionRowCache.ContainsKey(type))
                {
                    var param1 = Expression.Parameter(typeof(SurveyControl), "parent");
                    var param2 = Expression.Parameter(typeof(XmlNode), "configuration");
                    var ctor = type.GetConstructor(new[] { typeof(SurveyControl), typeof(XmlNode) });
                    var lambda = Expression.Lambda<Func<SurveyControl, XmlNode, SurveyQuestionRow>>(
                        Expression.New(ctor, param1, param2), param1, param2);
                    func = lambda.Compile();
                    surveyQuestionRowCache.Add(type, func);
                }
                else
                {
                    func = surveyQuestionRowCache[type];
                }
                    
                return func(parent, configuration);

            }
            throw new Exception("Type not found: " + key);
        }

        public static SurveyQuestionRow Create(Type type, SurveyControl parent, XmlNode configuration)
        {
            SurveyQuestionRow ctl = (SurveyQuestionRow)Reflection.CreateLocalObject(
                    type,
                    new Type[] { typeof(SurveyControl), typeof(XmlNode) },
                    new object[] { parent, configuration }
                );

            return ctl;
        }


    }
}